﻿//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using Microsoft.ResourceManagement.Samples.ResourceManagementClient.ExtensionIdentityManagementOperations;
using Microsoft.ResourceManagement.Samples.ResourceManagementClient.ResourceManagement;

namespace Microsoft.ResourceManagement.Samples.ResourceManagementClient.Utilities
{
    public sealed class ResourceManagementObjectFactory
    {
        private ResourceManagementObjectFactory()
        {

        }

        /// <summary>
        /// Constructs a resource management object from a given xml node
        /// </summary>
        /// <param name="parentNode">The root xml node of an xml representation of a resource management object.</param>
        /// <returns></returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode")]
        public static ResourceManagementObject CreateObject(XmlNode parentNode)
        {
            if (null == parentNode)
            {
                throw new ArgumentNullException("parentNode", "parentNode cannot be null");
            }

            XmlNode objectId = parentNode.SelectSingleNode("ObjectID",StaticSchemaManager.Instance.ResourceManagementNamespaceManager);
            String objectGuid = String.Empty;
            if (null != objectId && null != objectId.InnerText)
            {
                objectGuid = objectId.InnerText;
            }

            ResourceManagementObject newResourceManagementObject = new ResourceManagementObject(objectGuid, parentNode.Name);

            foreach(XmlNode child in parentNode.ChildNodes)
            {
                XmlAttribute nullAttribute = child.Attributes["nil", Constants.NamespaceXsdInstance];
                if (null != nullAttribute)
                {
                    if (nullAttribute.Value.ToUpperInvariant().Equals("TRUE"))
                    {
                        // The value is null, so we skip this
                        // The ResourceManagementObject will return null if you were expecting this
                        // Adding an attribute of the same name later will mark it ready for put requests
                        continue;
                    }
                }
                String attributeName = child.Name;
                if (null == newResourceManagementObject[attributeName])
                {
                    newResourceManagementObject[attributeName] = new ResourceManagementAttribute(attributeName, child.InnerText);
                }
                else
                {
                    ResourceManagementAttribute multiValuedAttribute = newResourceManagementObject[attributeName];
                    if (false == multiValuedAttribute.IsMultiValued)
                    {
                        // in this branch we incorrectly assumed that an attribute was a single valued attribute
                        // now we must unwind this decision by creating a new
                        // multi-valued attribute and adding in the existing value
                        ResourceManagementAttribute newMultiValuedAttribute = new ResourceManagementAttribute(true, attributeName);
                        newMultiValuedAttribute.AddMultiValue(multiValuedAttribute.AttributeSingleValue);
                        multiValuedAttribute = newMultiValuedAttribute;
                        newResourceManagementObject[attributeName] = multiValuedAttribute;
                    }
                    multiValuedAttribute.AddMultiValue(child.InnerText);
                }
            }
            // We note that this freshly changed object has no changed attributes since we're constructing it.
            // This is to enable a put request to identify which attributes the caller has modified
            newResourceManagementObject.ClearIsChanged();
            return newResourceManagementObject;
        }

        public static ResourceManagementObject CreateObject(BaseObjectSearchResponse searchResponse)
        {
            if (null == searchResponse || null == searchResponse.PartialAttributes)
            {
                throw new ArgumentNullException("searchResponse", "The Base Object Search Response must not be null");
            }

            // need to look ahead for the type and id, first
            String objectType = String.Empty;
            String objectId = String.Empty;
            foreach(PartialAttribute partialAttribute in searchResponse.PartialAttributes)
            {
                foreach (XmlNode partialAttributeValue in partialAttribute.Values)
                {
                    if (partialAttributeValue.Name.Equals("ObjectType"))
                    {
                        objectType = partialAttributeValue.InnerText;
                    }
                    if (partialAttributeValue.Name.Equals("ObjectID"))
                    {
                        objectId = partialAttributeValue.InnerText;
                    }
                }
            }

            // now we construct the object
            ResourceManagementObject newResourceManagementObject = new ResourceManagementObject(objectId, objectType);
            foreach(PartialAttribute partialAttribute in searchResponse.PartialAttributes)
            {
                if (partialAttribute.Values.Count <= 0)
                    continue;
                if (partialAttribute.Values.Count == 1)
                {
                    foreach (XmlNode partialAttributeValue in partialAttribute.Values)
                    {
                        newResourceManagementObject[partialAttributeValue.Name] = new ResourceManagementAttribute(partialAttributeValue.Name, partialAttributeValue.InnerText);
                    }
                }
                else
                {
                    List<Object > values = new List<Object >();
                    String name = String.Empty;
                    foreach (XmlNode partialAttributeValue in partialAttribute.Values)
                    {
                        name = partialAttributeValue.Name;
                        values.Add(partialAttributeValue.InnerText);
                    }

                    newResourceManagementObject[name] = new ResourceManagementAttribute(true, name);
                    foreach (Object o in values)
                    {
                        newResourceManagementObject[name].AddMultiValue(o);
                    }
                }
            }
            // We note that this freshly changed object has no changed attributes since we're constructing it.
            // This is to enable a put request to identify which attributes the caller has modified
            newResourceManagementObject.ClearIsChanged();
            return newResourceManagementObject;
        }
    }
}
